/**
 * @param {string} path
 * @returns {Boolean}
 */
export function isExternal(path) {
  return /^(https?:|mailto:|tel:)/.test(path)
}

export function isHttp(path) {
  return /^(https?:)/.test(path)
}

/**
 * @param {string} str
 * @returns {Boolean}
 */
export function validUsername(str) {
  const valid_map = ['admin', 'editor']
  return valid_map.indexOf(str.trim()) >= 0
}

/**
 * @param {string} url
 * @returns {Boolean}
 */
export function validURL(url) {
  const reg = new RegExp('^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$', 'i')
  return reg.test(url)
}

/**
 * @param {string} str
 * @returns {Boolean}
 */
export function validLowerCase(str) {
  const reg = /^[a-z]+$/
  return reg.test(str)
}

/**
 * @param {string} str
 * @returns {Boolean}
 */
export function validUpperCase(str) {
  const reg = /^[A-Z]+$/
  return reg.test(str)
}

/**
 * @param {string} str
 * @returns {Boolean}
 */
export function validAlphabets(str) {
  const reg = /^[A-Za-z]+$/
  return reg.test(str)
}

/**
 * @param {string} email
 * @returns {Boolean}
 */
export function validEmail(email) {
  const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
  return reg.test(email)
}

/**
 * @param {string} ip
 * @returns {Boolean}
 */
export function validIp(ip) {
  const reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
  return reg.test(ip)
}

/**
 * @param {string} port
 * @returns {Boolean}
 */
export function validPort(port) {
  const reg = /^([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])$/
  return reg.test(port)
}

/**
 * @param {string} str
 * @returns {Boolean}
 */
export function isString(str) {
  if (typeof str === 'string' || str instanceof String) {
    return true
  }
  return false
}

/**
 * @param {Number} num
 * @returns {Boolean}
 */
export function isNumber(num) {
  if (isNaN(num)) {
    return false
  }
  return typeof num === 'number'
}
export function isInt(num) {
  return isNumber(num) && parseInt(num, 10) === num
}
export function isFloat(num) {
  return isNumber(num) && !isInt(num)
}

/**
 * @param {Array} arg
 * @returns {Boolean}
 */
export function isArray(arg) {
  if (typeof Array.isArray === 'undefined') {
    return Object.prototype.toString.call(arg) === '[object Array]'
  }
  return Array.isArray(arg)
}

/**
 * 正数
 * @param {Number} num
 * @returns {Boolean}
 */
export function isPositiveNumber(num) {
  const reg = /^[+]{0,1}(\d+)$/
  return reg.test(num)
}

/**
 * 小数
 * @param {Number} num
 * @returns {Boolean}
 */
export function isDecimalNumber(num) {
  const reg = /^[-\+]?\d+(\.\d+)?$/
  return reg.test(num)
}

/**
 * 保留n位小数
 * @param {Number} num
 * @returns {Boolean}
 */
export function checkFloat(num, n) {
  const reg = new RegExp(`^([1-9]+[\d]*(.[0-9]{1,${n}})?)$`)
  return reg.test(num)
}

// 校验json
export function isJSON(str) {
  if (!str) {
    return true
  }
  if (typeof str == 'string' && /\{.*\}/.test(str)) {
    try {
      JSON.parse(str);
      return true;
    } catch (e) {
      return false;
    }
  }
  return false;  
}

// element-ui 表单校验 二次分装
const idcardReg = /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/
const latReg = /^(\-|\+)?([0-8]?\d{1}\.\d{0,8}|90\.0{0,8}|[0-8]?\d{1}|90)$/
const longReg = /^(\-|\+)?(((\d|[1-9]\d|1[0-7]\d|0{1,3})\.\d{0,8})|(\d|[1-9]\d|1[0-7]\d|0{1,3})|180\.0{0,8}|180)$/
const hexReg = /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i

const validateList = {
  required: function(tip = '', trigger) {
    return { required: true, message: `${tip}不能为空`, trigger: trigger }
  },
  req: function(tip = '', trigger) {
    return { required: true, message: `${tip}不能为空`, trigger: trigger }
  },
  port: function(tip, trigger) {
    return { validator: validator(validPort, '端口格式不正确'), trigger: trigger }
  },
  ip: function(tip, trigger) {
    return { validator: validator(validIp, 'IP格式不正确'), trigger: trigger }
  },
  email: function(tip, trigger) {
    return { validator: validator(validEmail, '邮箱格式不正确'), trigger: trigger }
  },
  url: function(tip, trigger) {
    return { validator: validator(validURL, 'url格式不正确'), trigger: trigger }
  },
  idCard: function(tip, trigger) {
    return { pattern: idcardReg, message: '请输入正确的身份证号', trigger: trigger }
  },
  number: function(tip, trigger) {
    return { validator: validator(isNumber, '请输入数字'), trigger: trigger }
  },
  int: function(tip, trigger) {
    return { validator: validator(isInt, '请输入正确的整数'), trigger: trigger }
  },
  phone: function(tip, trigger) {
    return { pattern: /^1[1|2|3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号', trigger: trigger }
  },
  hex: function(tip, trigger) {
    return { pattern: hexReg, message: '颜色格式不正确', trigger: trigger }
  },
  json: function(tip, trigger) {
    return { validator: validator(isJSON, 'json格式不正确'), trigger: trigger }
  },
  lat: function(tip, trigger) {
    return { pattern: latReg, message: '纬度格式不正确', trigger: trigger }
  },
  long: function(tip, trigger) {
    return { pattern: longReg, message: '经度格式不正确', trigger: trigger }
  },
  chinese: function(tip, trigger) {
    return { pattern: /^[\u2E80-\u9FFF]+$/, message: '只能输入汉字', trigger: trigger }
  },
  numStr: function(tip, trigger) {
    return { pattern: /^[0-9]+$/, message: '只能输入数字', trigger: trigger }
  },
  caseNumber: function(tip, trigger) {
    return { pattern: /^[0-9a-zA-Z]+$/, message: '只能输入字母或数字', trigger: trigger }
  },
  caseNumberSymbols: function(tip, trigger) {
    var reg = new RegExp("[0-9a-zA-Z`~!@#$^&*()=|{}':;',\\[\\].<>/?~！@#￥……&*（）——|{}【】‘；：”“'。，、？]")
    return { pattern: reg, message: '只能输入字母、符号或数字', trigger: trigger }
  },
  alphabets: function(tip, trigger) {
    return { validator: validator(validAlphabets, '只能输入字母'), trigger: trigger }
  },
  lowerCase: function(tip, trigger) {
    return { validator: validator(validLowerCase, '只能输入小写字母'), trigger: trigger }
  },
  upperCase: function(tip, trigger) {
    return { validator: validator(validUpperCase, '只能输入大写字母'), trigger: trigger }
  },
  max: function(len, trigger) {
    return { max: +len, message: `长度不能大于${len}个字符`, trigger: trigger }
  },
  min: function(len, trigger) {
    return { min: +len, message: `长度不能小于${len}个字符`, trigger: trigger }
  },
  mid: function(len, trigger) {
    const [min, max] = len.split('-')
    return { min: +min, max: +max, message: `字符长度需在${min} - ${max}之间`, trigger: trigger }
  },
  nmi: function(len, trigger) {
    return { validator: minNumb(len), trigger: trigger }
  },
  nmx: function(len, trigger) {
    return { validator: maxNumb(len), trigger: trigger }
  },
  arr: function(tip, trigger) {
    return { validator: (rule, value, callback) => {
      if (value.length == 0) {
        return callback(new Error('不能为空'))
      }
      callback()
    }, trigger: trigger }
  }
}
function validator(fn, tip) {
  tip = tip || '格式不正确'
  return (rule, value, callback) => {
    !fn(value) ? callback(new Error(tip)) : callback()
  }
}
function minNumb(len) {
  return (rule, value, callback) => {
    if (+value < +len) {
      const numb = '最小值为' + len
      return callback(new Error(numb))
    }
    callback()
  }
}
function maxNumb(len) {
  return (rule, value, callback) => {
    if (+value > +len) {
      const numb = '最大值为' + len
      return callback(new Error(numb))
    }
    callback()
  }
}
/**
 * 表单校验简化封装
 * @param {String|Array} rule
 * @param {String} tip 
 * @param {String|Array} trigger 
 * @returns {Array}
 */
export function elValidate(rule = 'required', tip = '', trigger = 'blur') {
  const arr = []
  if (isString(rule)) {
    rule = [rule]
  } else if (isArray(rule)) {
    rule = rule || []
  } else {
    return arr
  }
  for (let i = 0; i < rule.length; i++) {
    const _rule = validateList[rule[i]]
    if (_rule) {
      arr.push(_rule(tip, trigger))
    } else {
      const type = rule[i].slice(0, 3)
      const len = rule[i].slice(3)
      if (['min', 'max', 'mid', 'nmi', 'nmx'].includes(type)) {
        arr.push(validateList[type](len, trigger))
      }
    }
  }
  return arr
}

/**
 * elValidate 使用说明
 * 参数 
 * rule  字符串 或 数组，0个至多个校验，默认 'required'
 * tip 字符串， 字段名称
 * trigger  字符串 或 数组，触发方式，默认 'blur', 同elementui
 * 
 * 所含有的规则列表
 * required -- 必填
 * port -- 端口
 * ip -- ip
 * email -- 邮箱
 * url -- url，连接
 * idCard -- 身份证号
 * phone -- 手机号
 * number -- 数字 Number
 * hex -- 颜色，16进制
 * lat -- 纬度
 * long -- 经度
 * chinese -- 汉字
 * numStr -- 数字字符串
 * caseNumber -- 字母数字
 * caseNumberSymbols -- 字母数字符号
 * alphabets -- 字母，包含大小写
 * lowerCase -- 小写字母
 * upperCase -- 大写字母
 * max -- 字符串长度 上限，例：max30
 * min -- 字符串长度 下限，例：min5
 * mid -- 字符串长度 之间，例：mid5-30
 * 
 * 案例 
 this.rules = {
   name: this.elValidate(['required', 'max30'], ['blur', 'change'], '姓名'),
   phone: this.elValidate(['required', 'phone']),
   sex: this.elValidate()
 }
 */
